import re
import pywintypes

from ..win_control.control import Control
from ..win_control.form import Form
from .web_element import WebElement
from ..exceptions import CsClientError


class WebDocument(Control):
    '''
    网页文档操作类
    '''

    def state(self):
        '''
        获取当前网页的加载状态，invalid, loading, loaded, interactive, complete

        :Returns:
            返回当前网页的加载状态
        '''
        return self.control.State

    def path(self):
        '''
        获取pageurl的路径部分

        :Returns:
            返回pageurl的路径部分
        '''
        return self.control.Path

    def get_page_url(self):
        '''
        获取当前的url

        :Returns:
            返回当前的url
        '''
        return self.control.GetPageUrl

    def set_page_url(self, url):
        '''
        设置当前的url

        :Args:
         - url: 当前的url
        '''
        self.control.SetPageUrl(url)

    def page(self):
        '''
        获取pageurl的页面部分

        :Returns:
            返回pageurl的页面部分
        '''
        return self.control.Page

    def get_full_screen(self):
        '''
        获取当前是否全屏

        :Returns:
            全屏返回True，反之返回False
        '''
        return self.control.GetFullScreen

    def set_full_screen(self, is_full_screen):
        '''
        设置当前是否全屏

        :Args:
         - is_full_screen: 是否全屏，True or False
        '''
        self.control.SetFullScreen(is_full_screen)

    def domain(self):
        '''
        获取pageurl的域名部分

        :Returns:
            返回pageurl的域名部分
        '''
        return self.control.Domain

    def browser_version(self):
        '''
        获取浏览器版本

        :Returns:
            返回浏览器版本
        '''
        return self.control.BrowserVersion

    def browser_name(self):
        '''
        获取浏览器名称

        :Returns:
            返回浏览器名称
        '''
        return self.control.BrowserName

    def browser(self):
        '''
        获取浏览器窗体对象

        :Returns:
            返回浏览器窗体对象
        '''
        return Form(self.control.Browser)

    def check_duplicate_element_id(self):
        '''
        检查网页是否存在重复的元素id

        :Returns:
            有重复则返回重复的id，反之返回False
        '''
        result = self.control.CheckDuplicateElementIds
        if result:
            return self.control.GetDuplicateElementIds
        else:
            return result

    def close(self):
        '''
        关闭网页
        '''
        self.control.Close

    def execute_script(self, script):
        '''
        执行js语句

        :Args:
         - script: js语句

        :Returns:
            返回js语句返回的值
        '''
        return self.control.ExecuteScript(script)

    def get_html(self):
        '''
        获取当前页面的html

        :Returns:
            返回当前页面的html
        '''
        return self.control.GetHtml

    def navigate(self, url, wait_for_loaded=False, timeout=10000):
        '''
        打开url页面

        :Args:
         - url: url
         - wait_for_loaded: 是否等待页面加载，True or False
         - timeout: 等待页面加载完成的时间
        '''
        if wait_for_loaded and timeout:
            self.control.Navigate(url, wait_for_loaded, timeout)
        elif wait_for_loaded and not timeout:
            self.control.Navigate(url, wait_for_loaded)
        elif not wait_for_loaded:
            self.control.Navigate(url)
        else:
            raise CsClientError('参数错误！')

    def wait_for_document_loaded(self, timeout=10000):
        '''
        等待页面加载

        :Args:
         - timeout: 等待页面加载完成的时间
        '''
        if timeout:
            self.control.WaitForDocumentLoaded(timeout)
        else:
            self.control.WaitForDocumentLoaded

    # 对应selenium方法
    def find_element_by_attribute(self, by, value, assist='', timeout=10000):
        '''
        根据多属性查找当前元素节点下符合查找条件的元素集合，assist指的是辅助属性

        :Args:
         - by: 必须是'xpath'
         - value: ranorexpath
         - assist: 辅助属性，'属性名称:属性值'，支持多组属性，多组之间用逗号隔开
         - timeout: 查找元素的超时时间，在timeout时间内会不断的查找直到找到为止，超过timeout时间则不再继续查找

        :Returns:
            返回符合条件的元素，WebElement类型

        :Raises:
            CsClientError: 参数不正确

        :Example:
         - 例: ele_list = element.find_elements_by_attribute('xpath', '//input[@id="su"]', 'text:百度一下', 3)
        '''
        # if by.upper() == 'ID':
        #     value = '//*[#"{}"]'.format(value)
        # elif by.upper() == 'NAME':
        #     value = '//*[@name=\'{}\']'.format(value)
        # elif by.upper() == 'TAG NAME':
        #     value = '//{}'.format(value)
        # elif by.upper() == 'CLASS NAME':
        #     value = '//*[@class=\'{0}\' or @class~\'^{0} \' or @class~\' {0}$\' or @class~\' {0} \']'.format(
        #         value)
        # elif by.upper() == 'LINK TEXT':
        #     value = '//a[@text=\'{}\']'.format(value)
        # elif by.upper() == 'PARTIAL LINK TEXT':
        #     value = '//a[@text~\'{}\']'.format(value)
        # elif by.upper() == 'CSS SELECTOR':
        #     value = './/' + value
        #     # 替换分层符
        #     value = value.replace(' > ', '/')
        #     value = value.replace('>', '/')
        #     value = value.replace(' ', '//')
        #     # 替换后同级节点
        #     value = value.replace('~', '/following-sibling::')
        #     # 替换id属性
        #     id_list = re.findall(r'#([\w\-]+)', value)
        #     for id in id_list:
        #         value = re.sub(r'#' + id, '[#\'{}\']'.format(id), value)
        #     # 替换class属性
        #     class_list = re.findall(r'\.([\w\-]+)', value)
        #     for cl in class_list:
        #         value = re.sub(r'\.' + cl,
        #             '[@class=\'{0}\' or @class~\'^{0} \' or @class~\' {0}$\' or @class~\' {0} \']'.format(cl),
        #                        value, 1)
        #     # 替换其他属性
        #     type_list = re.findall(r'\[(\w+)=', value)
        #     for ty in type_list:
        #         value = value.replace(ty, '@' + ty, 1)
        #     # 连接多属性约束条件
        #     value = value.replace('][', ' and ')
        #     # 替换序号
        #     value = value.replace(':last-child', '[-1]')
        #     value = value.replace(':first-child', '[1]')
        #     child_list = re.findall(r':nth-child\((\d+)\)', value)
        #     for child in child_list:
        #         value = value.replace(':nth-child({})'.format(child), '[{}]'.format(child), 1)
        #     # 替换兄弟节点
        #     follow_list = re.findall(r'\+(\w+)', value)
        #     for follow in follow_list:
        #         value = re.sub(r'\+' + follow, '/following-sibling::{}[1]'.format(follow), value)
        #     print(value)
        # elif by.upper() == 'XPATH':
        #     pass
        # else:
        if by.upper() != 'XPATH' and by.upper() != 'RANOREXPATH':
            raise CsClientError('Ranorex只通过RanoreXpath访问元素！')
        if not assist:
            return self.find_element(value, timeout)
        else:
            element_list = self.find_elements_by_attribute(by, value, assist, timeout)
            if element_list:
                return element_list[0]
            else:
                raise CsClientError(by + ',' + value + ',' + assist + '属性对象没有找到!')

    def find_elements_by_attribute(self, by, value, assist='', timeout=10000):
        '''
        根据多属性查找当前元素节点下符合查找条件的元素集合，assist指的是辅助属性

        :Args:
         - by: 必须是'xpath'
         - value: ranorexpath
         - assist: 辅助属性，'属性名称:属性值'，支持多组属性，多组之间用逗号隔开
         - timeout: 查找元素的超时时间，在timeout时间内会不断的查找直到找到为止，超过timeout时间则不再继续查找

        :Returns:
            返回符合条件的元素集合，[WebElement]类型

        :Raises:
            CsClientError: 参数不正确

        :Example:
         - 例: ele_list = element.find_elements_by_attribute('xpath', '//input[@id="su"]', 'text:百度一下', 3)
        '''
        # if by.upper() == 'ID':
        #     value = '//*[#\'{}\']'.format(value)
        # elif by.upper() == 'NAME':
        #     value = '//*[@name=\'{}\']'.format(value)
        # elif by.upper() == 'TAG NAME':
        #     value = '//{}'.format(value)
        # elif by.upper() == 'CLASS NAME':
        #     value = '//*[@class=\'{0}\' or @class~\'^{0} \' or @class~\' {0}$\' or @class~\' {0} \']'.format(
        #         value)
        # elif by.upper() == 'LINK TEXT':
        #     value = '//a[text()=\'{}\']'.format(value)
        # elif by.upper() == 'PARTIAL LINK TEXT':
        #     value = '//a[contains(text(), \'{}\')]'.format(value)
        # elif by.upper() == 'CSS SELECTOR':
        #     value = './/' + value
        #     # 替换分层符
        #     value = value.replace(' > ', '/')
        #     value = value.replace('>', '/')
        #     value = value.replace(' ', '//')
        #     # 替换兄弟节点
        #     value = value.replace('~', '/following-sibling::')
        #     # 替换id属性
        #     id_list = re.findall(r'#([\w\-]+)', value)
        #     for id in id_list:
        #         value = re.sub(r'#' + id, '[#\'{}\']'.format(id), value)
        #     # 替换class属性
        #     class_list = re.findall(r'\.([\w\-]+)', value)
        #     for cl in class_list:
        #         value = re.sub(r'\.' + cl,
        #             '[@class=\'{0}\' or @class~\'^{0} \' or @class~\' {0}$\' or @class~\' {0} \']'.format(cl),
        #                        value, 1)
        #     # 替换其他属性
        #     type_list = re.findall(r'\[(\w+)=', value)
        #     for ty in type_list:
        #         value = value.replace(ty, '@' + ty, 1)
        #     # 连接多属性约束条件
        #     value = value.replace('][', ' and ')
        #     # 替换序号
        #     value = value.replace(':last-child', '[-1]')
        #     value = value.replace(':first-child', '[1]')
        #     child_list = re.findall(r':nth-child\((\d+)\)', value)
        #     for child in child_list:
        #         value = value.replace(':nth-child({})'.format(child), '[{}]'.format(child), 1)
        #     # 替换兄弟节点
        #     follow_list = re.findall(r'\+(\w+)', value)
        #     for follow in follow_list:
        #         value = re.sub(r'\+' + follow, '/following-sibling::{}[1]'.format(follow), value)
        #     print(value)
        # elif by.upper() == 'XPATH':
        #     pass
        # else:
        if by.upper() != 'XPATH' and by.upper() != 'RANOREXPATH':
            raise CsClientError('Ranorex只通过RanoreXpath访问元素！')
        if not assist:
            return self.find_elements(value, timeout)
        else:
            element_list = self.find_elements(value, timeout)
            if len(element_list) > 0:
                assist_list = assist.split(',')
                i = 0
                while i < len(element_list):
                    for e in assist_list:
                        index_number = e.index(':')
                        if e[0:index_number] == 'text':
                            re_str = '^' + e[index_number + 1:] + '$'
                            re_str = re_str.replace('(', '\(')
                            re_str = re_str.replace(')', '\)')
                            if e[index_number + 1:].startswith('.'):
                                re_str = re_str.strip('^')
                            if e[index_number + 1:].endswith('.*'):
                                re_str = re_str.strip('$')
                            e_html_text = element_list[i].get_inner_html()
                            e_text = re.sub('<[^<>]*>', '', e_html_text).strip()
                            if not e_text or not re.search(re_str, e_text):
                                element_list.remove(element_list[i])
                            else:
                                i += 1
                        elif e[0:index_number] == 'style':
                            re_str = e[index_number + 1:]
                            index_no = re_str.index(':')
                            element_style = element_list[i].get_style(re_str[0:index_no])
                            re_word = re_str[index_no + 1:].strip(';').strip()
                            if element_style == re_word:
                                i += 1
                            else:
                                element_list.remove(element_list[i])
                        else:
                            # 正则表达式中需要做设定，必须以给定的字符串打头和结尾
                            element_attr = element_list[i].get_attribute(e[0:index_number])
                            re_word = e[index_number + 1:]
                            if re_word not in element_attr.split(' '):
                                element_list.remove(element_list[i])
                            else:
                                i += 1
                return element_list
            else:
                return element_list

    def exist(self, by, value, assist='', timeout=10000):
        '''
        根据多属性查找当前元素节点下符合查找条件的元素集合，assist指的是辅助属性

        :Args:
         - by: 必须是'xpath'
         - value: ranorexpath
         - assist: 辅助属性，'属性名称:属性值'，支持多组属性，多组之间用逗号隔开
         - timeout: 查找元素的超时时间，在timeout时间内会不断的查找直到找到为止，超过timeout时间则不再继续查找

        :Returns:
            存在返回符合条件的元素，不存在返回None

        :Raises:
            CsClientError: 参数不正确

        :Example:
         - 例: ele = element.exist('xpath', '//input[@id="su"]', 'text:百度一下', 3)
        '''
        if by.upper() != 'XPATH':
            raise CsClientError('Ranorex只通过RanoreXpath访问元素！')
        try:
            if not assist:
                if self.is_element_exist(value, timeout):
                    return self.find_element(value, timeout)
                else:
                    return None
            else:
                element = self.find_element_by_attribute(by, value, assist, timeout)
                return element
        except CsClientError:
            return None

    def find_element(self, xpath, time=10000):
        '''
        根据相对路径查找元素，如果有多个控件符合，只返回第一个找到的控件

        :Args:
         - xpath: 相对此控件的Ranorexpath
         - time: 查找时间，默认为10S，单位ms

        :Returns:
            返回控件的对象
        '''
        try:
            webelement = self.control.FindElement(xpath, time)
            return WebElement(webelement)
        except pywintypes.com_error as msg:
            raise CsClientError(xpath + '对象查找出错：' + str(msg))

    def find_elements(self, xpath, time=10000):
        '''
        根据相对路径查找所有符合此Path的所有元素

        :Args:
         - xpath: 相对此控件的Ranorexpath
         - time: 查找时间，默认为10S，单位ms

        :Returns:
            返回控件的对象集合
        '''
        webelement_list = self.control.FindElements(xpath, time)
        return [WebElement(control) for control in webelement_list]

    def scroll_into_view(self, xpath):
        '''
        使元素可见

        :Args:
         - xpath: 控件的XPath

        :Returns:
            None
        '''
        try:
            js = "document.evaluate(\"{}\",document,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue.scrollIntoView()".format(
                xpath)
            self.execute_script(js)
        except:
            #执行script失败
            pass
